﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace Bangle.SerialPort
{
    public class SerialPortFactory
    {
        private static ConcurrentDictionary<string, Type> _dicTypeCache = new ConcurrentDictionary<string, Type>();
        private static ConcurrentDictionary<string, System.IO.Ports.SerialPort> _dicSerialPortCache = new ConcurrentDictionary<string, System.IO.Ports.SerialPort>();

        public static void Add(string name, Type serviceType)
        {
            _dicTypeCache.TryAdd(name, serviceType);
        }


        public void OpenAll(IServiceProvider serviceProvider)
        {
            var configuration = serviceProvider.GetService<IConfiguration>();
            var children = configuration.GetSection("SerialPort").GetChildren();
            foreach (var child in children)
            {
                var serialPort = new System.IO.Ports.SerialPort();
                serialPort.PortName = child.GetSection("PortName").Value;
                serialPort.BaudRate = 115200;//波特率
                serialPort.DataBits = 8;//数据位
                serialPort.StopBits = System.IO.Ports.StopBits.One;//停止位

                if (_dicTypeCache.ContainsKey(child.Key))
                {
                    var serviceType = _dicTypeCache[child.Key];
                    serialPort.DataReceived += async (sender, e) =>
                    {
                        using (var scope = serviceProvider.CreateScope())
                        {
                            var service = scope.ServiceProvider.GetService(serviceType);
                            if (service != null)
                            {
                                await ((ISerialPortService)service).DoAsync(serialPort);
                            }
                        }
                    };
                }
                try
                {
                    serialPort.Open();
                    if (_dicTypeCache.ContainsKey(child.Key))
                    {
                        var serviceType = _dicTypeCache[child.Key];
                        Task.Run(async () =>
                        {
                            byte[] buffer = new byte[serialPort.BytesToRead];
                            var data = serialPort.Read(buffer, 0, buffer.Length);
                            var service = (ISerialPortService)(serviceProvider.GetService(serviceType));
                            await service.OnOpenAsync(serialPort);
                        });
                    }

                    _dicSerialPortCache.TryAdd(child.Key, serialPort);
                }
                catch { }
            }
        }

        public System.IO.Ports.SerialPort GetSerialPort(string name = "Default")
        {
            return _dicSerialPortCache[name];
        }
    }
}
